Try..finally a inicializace promenne

Otázka od: Martin Burle

22. 10. 2002 16:34

Ahoj vsem,
nemam jasno v tom, kde vytvaret instanci objektu. Priklad:

try
   Buf := TMemoryStream.Create;
   ....
finally
   Buf.Free;
end;

takto mi to pripada spravne, lec kompilator ma za to, ze variable buf might
not have been initialized.
Jde se nejak teto hlasky trvale zbavit, pouze pro tento pripad? Nebo je snad
lepsi vytvorit objekt jeste pred try?
Diky,
Martin Burle, D6, W2k


Odpovedá: PeJaSoft

22. 10. 2002 18:05

Buf := TMemoryStream.Create;
try
   ....
finally
   Buf.Free;
end;

Tohle se kompilatoru libit bude.

S pozdravem

Petr Jarkovsky
pejasoft@post.cz

----- Original Message -----
From: "Martin Burle" <mburle2@volny.cz>
> Ahoj vsem,
> nemam jasno v tom, kde vytvaret instanci objektu. Priklad:
>
> try
> Buf := TMemoryStream.Create;
> ....
> finally
> Buf.Free;
> end;
>
> takto mi to pripada spravne, lec kompilator ma za to, ze variable buf
might
> not have been initialized.
> Jde se nejak teto hlasky trvale zbavit, pouze pro tento pripad? Nebo je
snad
> lepsi vytvorit objekt jeste pred try?
> Diky,
> Martin Burle, D6, W2k

Odpovedá: Petr Vones

22. 10. 2002 17:39

From: "Martin Burle" <mburle2@volny.cz>
> nemam jasno v tom, kde vytvaret instanci objektu. Priklad:
>
> try
> Buf := TMemoryStream.Create;
> ....
> finally
> Buf.Free;
> end;
>
> takto mi to pripada spravne, lec kompilator ma za to, ze variable buf might
> not have been initialized.
> Jde se nejak teto hlasky trvale zbavit, pouze pro tento pripad? Nebo je snad
> lepsi vytvorit objekt jeste pred try?

Takhle je to nesmyslne, protoze ti jde o to mit garantovane uvolneni toho
objektu. Teoreticky totiz muze vzniknout vyjimka i v konstruktoru. Spravne:

Buf := TMemoryStream.Create;
try
   ....
finally
  Buf.Free;
end;

Petr Vones

Odpovedá: Martin Cajbik

22. 10. 2002 16:39

Mozno je lepsie to napisat takto, vtedy by to nemalo hlasit nic

Buf:= nil;
try
    Buf := TMemoryStream.Create;
    ....
 finally
  if Buf <> nil then
    Buf.Free;
end;

MarCaNT (marcant@sct.sk)

> Ahoj vsem,
> nemam jasno v tom, kde vytvaret instanci objektu. Priklad:
>
> try
> Buf := TMemoryStream.Create;
> ....
> finally
> Buf.Free;
> end;
>
> takto mi to pripada spravne, lec kompilator ma za to, ze variable buf
might
> not have been initialized.
> Jde se nejak teto hlasky trvale zbavit, pouze pro tento pripad? Nebo je
snad
> lepsi vytvorit objekt jeste pred try?
> Diky,
> Martin Burle, D6, W2k
>


Odpovedá: Petr Vones

22. 10. 2002 17:31

From: "Martin Cajbik" <cajbik@sct.sk>
> Buf:= nil;
> try

Toto by melo smysl v pripade, ze chces snizit pocet vnorenych try..finally
bloku, napriklad:

var
  InputStream, OutputStream: TMemoryStream;
begin
  InputStream := TMemoryStream.Create;
  try
    OutputStream := TMemoryStream.Create;
    try

    finally
      OutputStream.Free;
    end;
  finally
    InputStream.Free;
  end;
end;

upraveno jako:

var
  InputStream, OutputStream: TMemoryStream;
begin
  OutputStream := nil;
  InputStream := TMemoryStream.Create;
  try
    OutputStream := TMemoryStream.Create;

  finally
    InputStream.Free;
    OutputStream.Free;
  end;
end;


> if Buf <> nil then
> Buf.Free;

Toto je nesmyslne, protoze metoda Free prave kontroluje zdali instance objektu
neni nil.

Petr Vones

Odpovedá: Martin Schayna

22. 10. 2002 17:23

----- Original Message -----
From: "Martin Burle" <mburle2@volny.cz>
> nemam jasno v tom, kde vytvaret instanci objektu. Priklad:
>
> try
> Buf := TMemoryStream.Create;
> ....
> finally
> Buf.Free;
> end;
>
> Jde se nejak teto hlasky trvale zbavit, pouze pro tento pripad? Nebo je snad
> lepsi vytvorit objekt jeste pred try?

Ano, pred try. Pokud behem volani constructoru dojde k vyjimce,
automaticky se zavola destructor takze neni treba osetrovat Create
pomoci try-finally.

V pripade podobnych nejasnosti je mozne kouknout na zdrojaky
napr. v (delphi)\Source\VCL, samozrejme krome rady RTFM
<g>.

Martin Schayna

Odpovedá: Martin Burle

22. 10. 2002 19:17

> Buf := TMemoryStream.Create;
> try
> ....
> finally
> Buf.Free;
> end;

Diky vsem, delal jsem to presne tak, tedy Create jeste pred try, ale nemel
jsem z toho uplne dobry pocit - ted uz jsem v klidu  . Zmatlo me, ze create
v bloku try.. jsem videl v nekolika cizich zdrojacich, nepochybne
zkusenejsich autoru. Tedy proto, ze jsem RTFS <G> (nebyl to holt zdrojak
VCL).

Martin Burle

Odpovedá: Viliam Mlich

23. 10. 2002 6:00

>> if Buf <> nil then
>> Buf.Free;

> Toto je nesmyslne, protoze metoda Free prave
> kontroluje zdali instance objektu neni nil.

Na take nieco sa moze spoliehat len samovrah. Ale my jeptisky si aj na
sviecku natahujeme prezervativ.

bye
vmlich

Odpovedá: Jan Sebelík

23. 10. 2002 7:27

> Odesílatel: Viliam Mlich <vmlich@mbox.vol.cz>
> >> if Buf <> nil then
> >> Buf.Free;
> > Toto je nesmyslne, protoze metoda Free prave
> > kontroluje zdali instance objektu neni nil.
>
> Na take nieco sa moze spoliehat len samovrah. Ale my jeptisky si aj na
> sviecku natahujeme prezervativ.
Jasne, ale pak bychom mohli psat (pro jistotu)

if buf<>nil then
  if buf<>nil then
    buf.Free;
 

Honza
=========================================
= HAES - RNDr. Jan Sebelik
= http://www.haes.cz
= Skolici a konzultacni stredisko pro Delphi a Win32
= Vojtiskova 206
= 507 81 Lazne Belohrad
= tel. 493 792 931 (mobil 776 347735)
=========================================

Odpovedá: Dalibor Toman

23. 10. 2002 8:19

>> >> if Buf <> nil then
>> >> Buf.Free;
>> > Toto je nesmyslne, protoze metoda Free prave
>> > kontroluje zdali instance objektu neni nil.
>>
>> Na take nieco sa moze spoliehat len samovrah. Ale my jeptisky si aj
na
>> sviecku natahujeme prezervativ.
>Jasne, ale pak bychom mohli psat (pro jistotu)
>
>if buf<>nil then
> if buf<>nil then
> buf.Free;

to uz postrada smysl uplne.
Kontrola na Buf <> NIL je sice v pripade classes a metody Free
nadbytecna ale dovedu si predstavit, ze nekdo pak bude prilis spolehat
na to, ze NIL pointr odchyti nejaky jiny kod i v situaci, kdy to
nebude pravda (staci misto Class pouzit napriklad pointr na Object s
definovanou vlastni metodou Free).

Nebo staci ve vlastni classes prepsat si vhodne metodu Free  

D. Toman

Odpovedá: eNca

23. 10. 2002 8:26



Viliam Mlich wrote:

>>> if Buf <> nil then
>>> Buf.Free;
>>>
>>>
>>Toto je nesmyslne, protoze metoda Free prave
>>kontroluje zdali instance objektu neni nil.
>>
>>
>
>Na take nieco sa moze spoliehat len samovrah. Ale my jeptisky si aj na
>sviecku natahujeme prezervativ.
>
>

procedure TObject.Free;
asm
        TEST EAX,EAX // jestlize je instance nil,
        JE @@exit // skoc na konec procedury
        MOV ECX,[EAX] // jinak volej destruktor
        MOV DL,1
        CALL dword ptr [ECX].vmtDestroy
@@exit:
end;

Na toto se klidne spolehnu a sebevrah nejsem. Pokud toto povazujes za
nedostatecne, tak doporucuju neprogramovat, protoze by ses nemel
spolehat ani na to, ze
i:=0; skutecne vynuluje promennou i  

eNca

Odpovedá: Viliam Mlich

23. 10. 2002 10:30

>>>> if Buf <> nil then
>>>> Buf.Free;

> procedure TObject.Free;

> Na toto se klidne spolehnu a sebevrah nejsem.

Ty sa na to kludne spoliehaj.

Hacik je v tom, ze tieto 2 riadky su v uplne inych suboroch a izolovany
zapis Buf.Free nehovori nic o tom, z coho je ten Buf, odvodeny. (Na to
vacsinou staci ocami skocit o par riadkov hore, to by este uslo.)

Ty si mozno pamatas, ze ked si to pisal, tak si metodu Free nemenil, ale
ten chudak, co by taky program po tebe musel udrziavat, by pri kazdom
probleme s uvolnovanim pamati musel kontrolovat, ci ta Free _nahodou_
nebola zmenena.

> tak doporucuju neprogramovat, protoze by ses nemel

:-) flejmovacie taktiky osvedcene z fida zaberaju aj na windozakov  
Este budes musiet precitat hodne sprav, kym sa naucis vynechavat osobne
utoky..

bye
vmlich

Odpovedá: Ondrej Kelle

23. 10. 2002 10:40

> Ty si mozno pamatas, ze ked si to pisal, tak si metodu Free
> nemenil, ale ten chudak, co by taky program po tebe musel
> udrziavat, by pri kazdom probleme s uvolnovanim pamati
> musel kontrolovat, ci ta Free _nahodou_ nebola zmenena.

Tiez sa mi to zda prehnane. Metoda Free je staticka, takze menit sa da
jedine prepisanim v potomkovi (a tym padom schovanim povodnej metody v
predkovi).
Za prve mi to pripada ako neskutocna prasacina, za druhe nenapada ma jediny
dovod, preco by mohlo byt vhodne/potrebne prepisovat metodu Free, ked je tam
k dispozicii virtualny destructor Destroy.
Ale v podstate mas pravdu, ze taka moznost existuje.

BTW. Staticke metody su na rozdiel od dynamickych resolvovane pocas
kompilacie, takze dva nasledovne kusky kodu, aj ked zdanlivo podobne, budu
sa chovat uplne rozdielne:

type
  TLeakingObject = class(TObject)
  public
    procedure Free;
  end;

procedure TLeakingObject.Free;
begin
  
OutputDebugString('Just because you''re paranoid it doesn''t mean they''re
not after you.');
end;

procedure Proc1;
var
  Obj: TLeakingObject;
begin
  Obj := TLeakingObject.Create;
  try
    ...
  finally
    Obj.Free; // memory leak v TLeakingObject.Free
  end;
end;

procedure Proc2;
var
  Obj: TObject;
begin
  Obj := TLeakingObject.Create;
  try
    ...
  finally
    Obj.Free; // uvolnenie pameti cez TObject.Free
  end;
end;

Pri prepisovani statickych metod vo vseobecnosti plati, ze si treba na ne
davat velky pozor, hrozi totiz, ze pripadna chyba bude tazko odhalitelna.
Ak si spravne spominam, podla Dannyho Thorpa v knihe "Delphi Component
Design"
tuto moznost Delphi poskytuje iba kvoli prechodnym stavom, ked sa
menia velke hierarchie tried a potrebujes mat kod rychlo "up and running".

TOndrej

Odpovedá: Petr Vones

23. 10. 2002 14:46

From: "Viliam Mlich" <vmlich@mbox.vol.cz>
> Ty si mozno pamatas, ze ked si to pisal, tak si metodu Free nemenil, ale
> ten chudak, co by taky program po tebe musel udrziavat, by pri kazdom
> probleme s uvolnovanim pamati musel kontrolovat, ci ta Free _nahodou_
> nebola zmenena.

Stejne tak kontrolovat, jestli treba nebyl zmeneny konstruktor a nepridal se
tam kod na zformatovani disku   Tohle je zkratka dobra demagogie. Pokud se
nekdo nekde snazil zmenit metodu Free tak je to samozrejme naprosto nesmyslna
vec, ktera by mela byt hned odhalena. Nejakym dalsim zbytecnym testovani nil
si moc nepomuzes, protoze tam mohl do Free pripsat treba
'if Day = 13 then
PInteger(nil)^ := 0' nebo nezavolal puvodni metodu Free a
mas hned dalsi
chybu.

Petr Vones

Odpovedá: Ludek ZITA

24. 10. 2002 20:48

Zdravim
Sledoval jsem s napetim tohle tema, ale nejsem z toho zrovna moudry  
No a zrovna potrebuji v threadu dynamicky vytvaret podle situace konexi k
databazi.
No a kdyz uz jednou objekt Database a Query vytvorim a prikonektim k DB, pak
ho chci pouzit vicekrat a nerusit ho pro kazdy dotaz.
Takze klasicky postup create..try...akce...finally...free neprichazi v
uvahu.
Udelal jsem si zjednoduseny pokus :

procedure TForm1.Button1Click(Sender: TObject);
var TS: TStringList;
  b: byte;
begin
  if CheckBox1.Checked then
  begin
    TS := TStringList.Create;
    TS.Text := 'BBB';
    ShowMessage(TS.Text);
  end
  else
  begin
    ShowMessage('AAA');
  end;
     TS.Free;
end;

Takze tohle samozrejme pri zaskrtnutem checkboxu funguje, ale pri
nezaskrtnutem to ZRUSI BUTTON !!!

Jedine co pomuze je iniciovat promennou TS na NIL.

begin
TS := nil;
........

Pak to fuguje korektne. Ma to sice logiku, promenne by se mely
inicializovat, ale nema to nejake uskali ohledne korektniho uvolnovani
pameti a pod. ?

Je spravne toto :

procedure TExecThread.Execute;
var
  ODBCDatabase: TODBCDatabase;
  ODBCQuery: TODBCQuery;

  procedure InitDB;
  begin
    if (ODBCDatabase <> nil) and (ODBCQuery <> nil) then
    begin
    // kontrola konexe
      if not ODBCDatabase.Connected then ODBCDatabase.Open;
    end else
    begin
    // pro jistotu kdyby byl uvolněn jen jeden objekt
      if ODBCDatabase <> nil then ODBCDatabase.Free;
      if ODBCQuery <> nil then ODBCQuery.Free;
    // vytvořit
      ODBCDatabase := TODBCDatabase.Create(Application);
      ODBCQuery := TODBCQuery.Create(Application);
      with ODBCQuery do
      begin
        Database := ODBCDatabase;
        CursorType := ctDynamic;
      end;
      ODBCDatabase.ConnStr.text := SysUtils.StringReplace(FConnStr, ';',
';'#13#10, [rfReplaceAll]);
      ODBCDatabase.Open;
    end;
  end;

begin
  ODBCDatabase := nil;
  ODBCQuery := nil;
  try
    // prvni blok
    case mainmeny of
      1:
        begin
     // kod bez konexe
        end;
      2: begin
      // kod s konexi
          InitDB;
          ODBCQuery.SQL.text := 'select .....';
          ODBCQuery.Open;
         // .......
        end;
    end;

    // druhý blok
    case krok of
      1:
        begin
        // kod bez konexe
        end;
      2: begin
         // kod s konexi
          InitDB;
          ODBCQuery.SQL.text := 'select .....';
          ODBCQuery.Open;
         // .......
        end;
    end;
    // pro jistotu pozavirame
    if ODBCQuery.Active then ODBCQuery.Close;
    if ODBCDatabase.Connected then ODBCDatabase.Close;
  finally
  // zrusime
    if ODBCDatabase <> nil then ODBCDatabase.Free;
    if ODBCQuery <> nil then ODBCQuery.Free;
  end;
end;



Ve skutecnosti je to mnohem kosatejsi a k databazi se bud vubec
nepristoupi, nebo se otevira v nekolika ruznych mistech.

Dik
Ludek


----- Original Message -----
From: "Petr Vones" <pvones@mbox.vol.cz>
> From: "Martin Cajbik" <cajbik@sct.sk>
> > Buf:= nil;
> > try
>
> Toto by melo smysl v pripade, ze chces snizit pocet vnorenych try..finally
> bloku, napriklad:
....

Odpovedá: Lebeda David

25. 10. 2002 5:59

> procedure TForm1.Button1Click(Sender: TObject);
> var TS: TStringList;
> b: byte;
> begin
> if CheckBox1.Checked then
> begin
> TS := TStringList.Create;
> TS.Text := 'BBB';
> ShowMessage(TS.Text);
> end
> else
> begin
> ShowMessage('AAA');
> end;
> TS.Free;
> end;
>
> Takze tohle samozrejme pri zaskrtnutem checkboxu funguje, ale pri
> nezaskrtnutem to ZRUSI BUTTON !!!

Hm, pokud neni zaskrtnuty checkbox, tak se jen zobrazi message 'AAA' a nasledne

se zavola free na TS. Jakozto neinicializovana promenna obsahuje zrejme nahodny

obsah, a proto se da tezko predvidat, co ten posledni radek vyvede. Spis bych
cekal
Access violation.

Reseni ale nespociva podle me v inicializaci na nil, ale v uprave logiky veci
tak, aby
se lokalni promenna uvolnovala jinde - uvnitr ifu, kde se TS vytvari apod.
Takhle
okus o vytvoreni probehne jen nekdy, zatimco uvolneni vzdy, a to je potreba
odstranit.

Pokud jsem nepochopil, k cemu tento prikladek smeroval, tak se omlouvam.

David Lebeda

Odpovedá: Lubos Urban

25. 10. 2002 8:30

Je to zaujimave ja som to skusil takto:

procedure TForm1.Button1Click(Sender: TObject);
var TS: TStringList;
begin
  TS.Free;
end;

a Cela Forma posla niekde ale netusim kde lebo to neukoncilo aplikaciu

no a ked som to krokoval tak som sa dostal priamo sem

procedure TObject.Free;
asm
        TEST EAX,EAX
        JE @@exit
        MOV ECX,[EAX]
        MOV DL,1
        CALL dword ptr [ECX].vmtDestroy
@@exit:
end;

a nie do destruktoru TStringListu;

Ked mi toto niekto vysvetli ze co robi ten kusok asembleru a preco to
nepadlo na destruktore TStringListu s AccesViolation

destructor TStringList.Destroy;
begin
  FOnChange := nil;
  FOnChanging := nil;
  inherited Destroy;
  if FCount <> 0 then Finalize(FList^[0], FCount);
  FCount := 0;
  SetCapacity(0);
end;

kde sa pristupuje k premennym triedy (FCount, FOnChanging .. ) ktore pri
neinstancovanych triedach by sa maly odkazovat len niekde do nealokovanej
pamate, budem vam povdacny  

----- Original Message -----
From: "Ludek ZITA" <konference@sales.cz>
To: <delphi-l@clexpert.cz>
Sent: Thursday, October 24, 2002 9:20 PM
Subject: Re: Try..finally a inicializace promenne


> Zdravim
> Sledoval jsem s napetim tohle tema, ale nejsem z toho zrovna moudry  
> No a zrovna potrebuji v threadu dynamicky vytvaret podle situace konexi k
> databazi.
> No a kdyz uz jednou objekt Database a Query vytvorim a prikonektim k DB,
pak
> ho chci pouzit vicekrat a nerusit ho pro kazdy dotaz.
> Takze klasicky postup create..try...akce...finally...free neprichazi v
> uvahu.
> Udelal jsem si zjednoduseny pokus :
>
> procedure TForm1.Button1Click(Sender: TObject);
> var TS: TStringList;
> b: byte;
> begin
> if CheckBox1.Checked then
> begin
> TS := TStringList.Create;
> TS.Text := 'BBB';
> ShowMessage(TS.Text);
> end
> else
> begin
> ShowMessage('AAA');
> end;
> TS.Free;
> end;
>
> Takze tohle samozrejme pri zaskrtnutem checkboxu funguje, ale pri
> nezaskrtnutem to ZRUSI BUTTON !!!
>
> Jedine co pomuze je iniciovat promennou TS na NIL.
>
> begin
> TS := nil;
> ........
>
> Pak to fuguje korektne. Ma to sice logiku, promenne by se mely
> inicializovat, ale nema to nejake uskali ohledne korektniho uvolnovani
> pameti a pod. ?
>
> Je spravne toto :
>
> procedure TExecThread.Execute;
> var
> ODBCDatabase: TODBCDatabase;
> ODBCQuery: TODBCQuery;
>
> procedure InitDB;
> begin
> if (ODBCDatabase <> nil) and (ODBCQuery <> nil) then
> begin
> // kontrola konexe
> if not ODBCDatabase.Connected then ODBCDatabase.Open;
> end else
> begin
> // pro jistotu kdyby byl uvolněn jen jeden objekt
> if ODBCDatabase <> nil then ODBCDatabase.Free;
> if ODBCQuery <> nil then ODBCQuery.Free;
> // vytvořit
> ODBCDatabase := TODBCDatabase.Create(Application);
> ODBCQuery := TODBCQuery.Create(Application);
> with ODBCQuery do
> begin
> Database := ODBCDatabase;
> CursorType := ctDynamic;
> end;
> ODBCDatabase.ConnStr.text := SysUtils.StringReplace(FConnStr, ';',
> ';'#13#10, [rfReplaceAll]);
> ODBCDatabase.Open;
> end;
> end;
>
> begin
> ODBCDatabase := nil;
> ODBCQuery := nil;
> try
> // prvni blok
> case mainmeny of
> 1:
> begin
> // kod bez konexe
> end;
> 2: begin
> // kod s konexi
> InitDB;
> ODBCQuery.SQL.text := 'select .....';
> ODBCQuery.Open;
> // .......
> end;
> end;
>
> // druhý blok
> case krok of
> 1:
> begin
> // kod bez konexe
> end;
> 2: begin
> // kod s konexi
> InitDB;
> ODBCQuery.SQL.text := 'select .....';
> ODBCQuery.Open;
> // .......
> end;
> end;
> // pro jistotu pozavirame
> if ODBCQuery.Active then ODBCQuery.Close;
> if ODBCDatabase.Connected then ODBCDatabase.Close;
> finally
> // zrusime
> if ODBCDatabase <> nil then ODBCDatabase.Free;
> if ODBCQuery <> nil then ODBCQuery.Free;
> end;
> end;
>
>
>
> Ve skutecnosti je to mnohem kosatejsi a k databazi se bud vubec
> nepristoupi, nebo se otevira v nekolika ruznych mistech.
>
> Dik
> Ludek
>
>
> ----- Original Message -----
> From: "Petr Vones" <pvones@mbox.vol.cz>
> > From: "Martin Cajbik" <cajbik@sct.sk>
> > > Buf:= nil;
> > > try
> >
> > Toto by melo smysl v pripade, ze chces snizit pocet vnorenych
try..finally
> > bloku, napriklad:
> ....
>
>
>

Odpovedá: Petr Langer

25. 10. 2002 9:19

Tak presne na toto jsem se ptal nedavno (asi tri ctyri dny zpatky) tady v
konferenci  . Pokud to pouzijes jako lokalni promenou, tak na zacatku, v
begin NENI objekt = nil, takze to na free vyhuci.

petr

----- Original Message -----
From: "Lubos Urban" <Lubos.Urban@visicom.sk>
To: <delphi-l@clexpert.cz>
Sent: Friday, October 25, 2002 9:05 AM
Subject: Re: Try..finally a inicializace promenne


> Je to zaujimave ja som to skusil takto:
>
> procedure TForm1.Button1Click(Sender: TObject);
> var TS: TStringList;
> begin
> TS.Free;
> end;
>
> a Cela Forma posla niekde ale netusim kde lebo to neukoncilo aplikaciu
>
> no a ked som to krokoval tak som sa dostal priamo sem
>
> procedure TObject.Free;
> asm
> TEST EAX,EAX
> JE @@exit
> MOV ECX,[EAX]
> MOV DL,1
> CALL dword ptr [ECX].vmtDestroy
> @@exit:
> end;
>
> a nie do destruktoru TStringListu;
>
> Ked mi toto niekto vysvetli ze co robi ten kusok asembleru a preco to
> nepadlo na destruktore TStringListu s AccesViolation
>
> destructor TStringList.Destroy;
> begin
> FOnChange := nil;
> FOnChanging := nil;
> inherited Destroy;
> if FCount <> 0 then Finalize(FList^[0], FCount);
> FCount := 0;
> SetCapacity(0);
> end;
>
> kde sa pristupuje k premennym triedy (FCount, FOnChanging .. ) ktore pri
> neinstancovanych triedach by sa maly odkazovat len niekde do nealokovanej
> pamate, budem vam povdacny  
>
> ----- Original Message -----
> From: "Ludek ZITA" <konference@sales.cz>
> To: <delphi-l@clexpert.cz>
> Sent: Thursday, October 24, 2002 9:20 PM
> Subject: Re: Try..finally a inicializace promenne
>
>
> > Zdravim
> > Sledoval jsem s napetim tohle tema, ale nejsem z toho zrovna moudry  
> > No a zrovna potrebuji v threadu dynamicky vytvaret podle situace konexi
k
> > databazi.
> > No a kdyz uz jednou objekt Database a Query vytvorim a prikonektim k DB,
> pak
> > ho chci pouzit vicekrat a nerusit ho pro kazdy dotaz.
> > Takze klasicky postup create..try...akce...finally...free neprichazi v
> > uvahu.
> > Udelal jsem si zjednoduseny pokus :
> >
> > procedure TForm1.Button1Click(Sender: TObject);
> > var TS: TStringList;
> > b: byte;
> > begin
> > if CheckBox1.Checked then
> > begin
> > TS := TStringList.Create;
> > TS.Text := 'BBB';
> > ShowMessage(TS.Text);
> > end
> > else
> > begin
> > ShowMessage('AAA');
> > end;
> > TS.Free;
> > end;
> >
> > Takze tohle samozrejme pri zaskrtnutem checkboxu funguje, ale pri
> > nezaskrtnutem to ZRUSI BUTTON !!!
> >
> > Jedine co pomuze je iniciovat promennou TS na NIL.
> >
> > begin
> > TS := nil;
> > ........
> >
> > Pak to fuguje korektne. Ma to sice logiku, promenne by se mely
> > inicializovat, ale nema to nejake uskali ohledne korektniho uvolnovani
> > pameti a pod. ?
> >
> > Je spravne toto :
> >
> > procedure TExecThread.Execute;
> > var
> > ODBCDatabase: TODBCDatabase;
> > ODBCQuery: TODBCQuery;
> >
> > procedure InitDB;
> > begin
> > if (ODBCDatabase <> nil) and (ODBCQuery <> nil) then
> > begin
> > // kontrola konexe
> > if not ODBCDatabase.Connected then ODBCDatabase.Open;
> > end else
> > begin
> > // pro jistotu kdyby byl uvolněn jen jeden objekt
> > if ODBCDatabase <> nil then ODBCDatabase.Free;
> > if ODBCQuery <> nil then ODBCQuery.Free;
> > // vytvořit
> > ODBCDatabase := TODBCDatabase.Create(Application);
> > ODBCQuery := TODBCQuery.Create(Application);
> > with ODBCQuery do
> > begin
> > Database := ODBCDatabase;
> > CursorType := ctDynamic;
> > end;
> > ODBCDatabase.ConnStr.text := SysUtils.StringReplace(FConnStr, ';',
> > ';'#13#10, [rfReplaceAll]);
> > ODBCDatabase.Open;
> > end;
> > end;
> >
> > begin
> > ODBCDatabase := nil;
> > ODBCQuery := nil;
> > try
> > // prvni blok
> > case mainmeny of
> > 1:
> > begin
> > // kod bez konexe
> > end;
> > 2: begin
> > // kod s konexi
> > InitDB;
> > ODBCQuery.SQL.text := 'select .....';
> > ODBCQuery.Open;
> > // .......
> > end;
> > end;
> >
> > // druhý blok
> > case krok of
> > 1:
> > begin
> > // kod bez konexe
> > end;
> > 2: begin
> > // kod s konexi
> > InitDB;
> > ODBCQuery.SQL.text := 'select .....';
> > ODBCQuery.Open;
> > // .......
> > end;
> > end;
> > // pro jistotu pozavirame
> > if ODBCQuery.Active then ODBCQuery.Close;
> > if ODBCDatabase.Connected then ODBCDatabase.Close;
> > finally
> > // zrusime
> > if ODBCDatabase <> nil then ODBCDatabase.Free;
> > if ODBCQuery <> nil then ODBCQuery.Free;
> > end;
> > end;
> >
> >
> >
> > Ve skutecnosti je to mnohem kosatejsi a k databazi se bud vubec
> > nepristoupi, nebo se otevira v nekolika ruznych mistech.
> >
> > Dik
> > Ludek
> >
> >
> > ----- Original Message -----
> > From: "Petr Vones" <pvones@mbox.vol.cz>
> > > From: "Martin Cajbik" <cajbik@sct.sk>
> > > > Buf:= nil;
> > > > try
> > >
> > > Toto by melo smysl v pripade, ze chces snizit pocet vnorenych
> try..finally
> > > bloku, napriklad:
> > ....
> >
> >
> >
>
>
>


Odpovedá: Lubos Urban

25. 10. 2002 8:42

No tak uz som dostal vysvetlenie  

Kedze pri instanciovani objektu sa vytvaraju iba jeho data a nie metody,
ktore su pre vsetky objekty tej istej classy spolocne, tak mozme zavolat
hociaku funckciu aj neinstancoivaneho objektu (Free) ktora ako prvy
parameter dostane self co je vlastne parameter na objekt ktory funkciu vola.
Kedze v Delphi nie su lokalne premenne automaticky nastavovane na defaultne
hodnoty na rozdiel od premennych deklarovanych v triede vyzera to asi
nesledovne ak sa nemylim:

procedure TForm1.Button1Click(Sender: TObject);
var TS: TStringList;
begin
  // TS nieje nil;
  TS.Free;
end

 procedure TObject.Free;
 asm
         TEST EAX,EAX
         JE @@exit
// porovnanie ci EAX prvy parameter funkcie (self) nie je 0 (nil)
// a kedze pri lokalnych premmeny ich hodnoty niesu nastavovane na nil
// tak tam nil nieje a funkcia nekonci a pokracuje
// a ked mame smolku tak v EAX je nejaka platna adresa napr na Formu
// alebo nejaku inu komponentu a zdestruujde sa ta  
         MOV ECX,[EAX]
         MOV DL,1
         CALL dword ptr [ECX].vmtDestroy
 @@exit:
 end;

==========================
ak by bola TS delklarovana v triede TForm1 vypadalo by to asi takto:

procedure TForm1.Button1Click(Sender: TObject);
begin
  // TS je nil lebo premenne deklarovane v triede su automaticky
inicializovane na defaultne hodnoty
  // v tomto pripade nil
  TS.Free;
end

 procedure TObject.Free;
 asm
         TEST EAX,EAX
         JE @@exit
// porovnanie ci EAX prvy parameter funkcie (self) nie je 0 (nil)
// EAX je 0 (nil) funcia konci nic sa nedestrojuje
         MOV ECX,[EAX]
         MOV DL,1
         CALL dword ptr [ECX].vmtDestroy
 @@exit:
 end;

=========================

Zaver: Vzdy inicializovat lokalne premenne, najma ak su to instancie tried
 


----- Original Message -----
From: "Lubos Urban" <Lubos.Urban@visicom.sk>
To: <delphi-l@clexpert.cz>
Sent: Friday, October 25, 2002 9:05 AM
Subject: Re: Try..finally a inicializace promenne


> Je to zaujimave ja som to skusil takto:
>
> procedure TForm1.Button1Click(Sender: TObject);
> var TS: TStringList;
> begin
> TS.Free;
> end;
>
> a Cela Forma posla niekde ale netusim kde lebo to neukoncilo aplikaciu
>
> no a ked som to krokoval tak som sa dostal priamo sem
>
> procedure TObject.Free;
> asm
> TEST EAX,EAX
> JE @@exit
> MOV ECX,[EAX]
> MOV DL,1
> CALL dword ptr [ECX].vmtDestroy
> @@exit:
> end;
>
> a nie do destruktoru TStringListu;
>
> Ked mi toto niekto vysvetli ze co robi ten kusok asembleru a preco to
> nepadlo na destruktore TStringListu s AccesViolation
>
> destructor TStringList.Destroy;
> begin
> FOnChange := nil;
> FOnChanging := nil;
> inherited Destroy;
> if FCount <> 0 then Finalize(FList^[0], FCount);
> FCount := 0;
> SetCapacity(0);
> end;
>
> kde sa pristupuje k premennym triedy (FCount, FOnChanging .. ) ktore pri
> neinstancovanych triedach by sa maly odkazovat len niekde do nealokovanej
> pamate, budem vam povdacny  
>
> ----- Original Message -----
> From: "Ludek ZITA" <konference@sales.cz>
> To: <delphi-l@clexpert.cz>
> Sent: Thursday, October 24, 2002 9:20 PM
> Subject: Re: Try..finally a inicializace promenne
>
>
> > Zdravim
> > Sledoval jsem s napetim tohle tema, ale nejsem z toho zrovna moudry  
> > No a zrovna potrebuji v threadu dynamicky vytvaret podle situace konexi
k
> > databazi.
> > No a kdyz uz jednou objekt Database a Query vytvorim a prikonektim k DB,
> pak
> > ho chci pouzit vicekrat a nerusit ho pro kazdy dotaz.
> > Takze klasicky postup create..try...akce...finally...free neprichazi v
> > uvahu.
> > Udelal jsem si zjednoduseny pokus :
> >
> > procedure TForm1.Button1Click(Sender: TObject);
> > var TS: TStringList;
> > b: byte;
> > begin
> > if CheckBox1.Checked then
> > begin
> > TS := TStringList.Create;
> > TS.Text := 'BBB';
> > ShowMessage(TS.Text);
> > end
> > else
> > begin
> > ShowMessage('AAA');
> > end;
> > TS.Free;
> > end;
> >
> > Takze tohle samozrejme pri zaskrtnutem checkboxu funguje, ale pri
> > nezaskrtnutem to ZRUSI BUTTON !!!
> >
> > Jedine co pomuze je iniciovat promennou TS na NIL.
> >
> > begin
> > TS := nil;
> > ........
> >
> > Pak to fuguje korektne. Ma to sice logiku, promenne by se mely
> > inicializovat, ale nema to nejake uskali ohledne korektniho uvolnovani
> > pameti a pod. ?
> >
> > Je spravne toto :
> >
> > procedure TExecThread.Execute;
> > var
> > ODBCDatabase: TODBCDatabase;
> > ODBCQuery: TODBCQuery;
> >
> > procedure InitDB;
> > begin
> > if (ODBCDatabase <> nil) and (ODBCQuery <> nil) then
> > begin
> > // kontrola konexe
> > if not ODBCDatabase.Connected then ODBCDatabase.Open;
> > end else
> > begin
> > // pro jistotu kdyby byl uvolněn jen jeden objekt
> > if ODBCDatabase <> nil then ODBCDatabase.Free;
> > if ODBCQuery <> nil then ODBCQuery.Free;
> > // vytvořit
> > ODBCDatabase := TODBCDatabase.Create(Application);
> > ODBCQuery := TODBCQuery.Create(Application);
> > with ODBCQuery do
> > begin
> > Database := ODBCDatabase;
> > CursorType := ctDynamic;
> > end;
> > ODBCDatabase.ConnStr.text := SysUtils.StringReplace(FConnStr, ';',
> > ';'#13#10, [rfReplaceAll]);
> > ODBCDatabase.Open;
> > end;
> > end;
> >
> > begin
> > ODBCDatabase := nil;
> > ODBCQuery := nil;
> > try
> > // prvni blok
> > case mainmeny of
> > 1:
> > begin
> > // kod bez konexe
> > end;
> > 2: begin
> > // kod s konexi
> > InitDB;
> > ODBCQuery.SQL.text := 'select .....';
> > ODBCQuery.Open;
> > // .......
> > end;
> > end;
> >
> > // druhý blok
> > case krok of
> > 1:
> > begin
> > // kod bez konexe
> > end;
> > 2: begin
> > // kod s konexi
> > InitDB;
> > ODBCQuery.SQL.text := 'select .....';
> > ODBCQuery.Open;
> > // .......
> > end;
> > end;
> > // pro jistotu pozavirame
> > if ODBCQuery.Active then ODBCQuery.Close;
> > if ODBCDatabase.Connected then ODBCDatabase.Close;
> > finally
> > // zrusime
> > if ODBCDatabase <> nil then ODBCDatabase.Free;
> > if ODBCQuery <> nil then ODBCQuery.Free;
> > end;
> > end;
> >
> >
> >
> > Ve skutecnosti je to mnohem kosatejsi a k databazi se bud vubec
> > nepristoupi, nebo se otevira v nekolika ruznych mistech.
> >
> > Dik
> > Ludek
> >
> >
> > ----- Original Message -----
> > From: "Petr Vones" <pvones@mbox.vol.cz>
> > > From: "Martin Cajbik" <cajbik@sct.sk>
> > > > Buf:= nil;
> > > > try
> > >
> > > Toto by melo smysl v pripade, ze chces snizit pocet vnorenych
> try..finally
> > > bloku, napriklad:
> > ....
> >
> >
> >
>
>
>

Odpovedá: Lukas Gebauer

25. 10. 2002 8:51

> destructor TStringList.Destroy;
> begin
> FOnChange := nil;
> FOnChanging := nil;
> inherited Destroy;
> if FCount <> 0 then Finalize(FList^[0], FCount);
> FCount := 0;
> SetCapacity(0);
> end;

Tak ty nejdrive ten objekt peclive zlikvidujes (tim inherited
Destroy), a pak se snazis pristupovat k jeho promennym (FCount) a
jeste navic pristupovat k jeho metodam (setCapacity).. to preci musi
zbuchnout, ne?  



-- Lukas Gebauer.

E-mail: gebauerl@mlp.cz
http://www.ararat.cz/synapse/ - Synapse Delphi and Kylix TCP/IP Lib.

Odpovedá: Lubos Urban

25. 10. 2002 9:07

To je original Borlandovsky zdrojak (classes.pas  


----- Original Message -----
From: "Lukas Gebauer" <gebylist@mlp.cz>
To: <delphi-l@clexpert.cz>
Sent: Friday, October 25, 2002 9:41 AM
Subject: Re: Try..finally a inicializace promenne


> > destructor TStringList.Destroy;
> > begin
> > FOnChange := nil;
> > FOnChanging := nil;
> > inherited Destroy;
> > if FCount <> 0 then Finalize(FList^[0], FCount);
> > FCount := 0;
> > SetCapacity(0);
> > end;
>
> Tak ty nejdrive ten objekt peclive zlikvidujes (tim inherited
> Destroy), a pak se snazis pristupovat k jeho promennym (FCount) a
> jeste navic pristupovat k jeho metodam (setCapacity).. to preci musi
> zbuchnout, ne?  
>
>
>
> -- Lukas Gebauer.
>
> E-mail: gebauerl@mlp.cz
> http://www.ararat.cz/synapse/ - Synapse Delphi and Kylix TCP/IP Lib.
>
>
>

Odpovedá: Ondrej Kelle

25. 10. 2002 9:37

> procedure TForm1.Button1Click(Sender: TObject);
> var TS: TStringList;
> begin
> TS.Free;
> end;
>
> a Cela Forma posla niekde ale netusim kde lebo to neukoncilo aplikaciu
>
> no a ked som to krokoval tak som sa dostal priamo sem
>
> procedure TObject.Free;
> asm
> TEST EAX,EAX
> JE @@exit
> MOV ECX,[EAX]
> MOV DL,1
> CALL dword ptr [ECX].vmtDestroy
> @@exit:
> end;
>
> a nie do destruktoru TStringListu;
>
> Ked mi toto niekto vysvetli ze co robi ten kusok asembleru a preco to
> nepadlo na destruktore TStringListu s AccesViolation

ten kusok asembleru robi toto:

procedure TObject.Free;
begin
  if Self <> nil then
    Destroy;
end;

Cize volas proceduru Free, ktora skontroluje, ci je dana premenna nil, a ak
nie je, zavola virtualny Destroy, tzn. vo VMT (virtual method table) danej
instancie sa vyhlada adresa Destroy posledneho potomka, ktory overridol
Destroy a ta sa zavola. Ked je ten pointer neinicializovany, potom aj jeho
VMT je sada divokych pointrov  

VMT ma myslim negativne offsety od Self, takze je mozne, ze to na tych
adresach nahodou naslo odkaz na Destroy toho formulara. Tam si potom dostal
AV pretoze nie je mozne destruovat windowed control v kontexte spracovania
spravy (WM_LBUTTONUP) Ale to su uz dohady. Skratka, neinicializovany pointer
ukazuje na blok pameti s nedefinovanym obsahom, takze pri jeho pouziti sa
moze stat _cokolvek_.
Jedna stara cinska kliatba vraj znela "Nech je Tvoj zivot zaujimavy".  

HTH
TOndrej

Odpovedá: Števlík Marián

25. 10. 2002 10:45

Ak sa mozem pripojit do diskusie, tak by som sa chcel tiez nieco spytat
ohladom try ... finally
Majme nieco taketo:

var
  Obj1: TObj1;
  Obj2: TObj2;
begin
  Obj1 := TObj1.Create(...);
  try
    try
      ...
      if (NejakaPodmienka) then
      begin
        Obj2 := TObj2.Create(...);
        try
          ...
        finally
          Obj2.Free;
        end;
      end;
      ...
    except
      ShowMessage('Chyba!');
    end;
  finally
    Obj1.Free;
  end;
end;

No a otazka znie
Ak sa vyskytne nejaka chyba medzi try ... finally pre Obj2 tak sa odchyti az
vtom jedinom except, ale je otazne ci sa predtym este zavola to Obj2.Free v
jeho finally, alebo sa rovno skoci do except a Obj2 ostane vysiet v pamati?

Stevlik Marian
Software Development Specialist
MERLIN
Stefanikova 32
150 00 Prague 5
Czech Republic
e-mail: marian.stevlik@merlin.cz
tel: +420 241010111 (181)
fax: +420 241010165
ICQ: 38493645

Odpovedá: Petr Langer

25. 10. 2002 11:02

zavola se v kazdem pripade, ale jak jsi spravne uvedl, tak tam ta chyba
neskonci, ale predava s pak dal az to nejblizsiho except.

petr

----- Original Message -----
From: "Števlík Marián" <Marian.Stevlik@merlin.cz>
To: <delphi-l@clexpert.cz>
Sent: Friday, October 25, 2002 11:02 AM
Subject: RE: Try..finally a inicializace promenne


> Ak sa mozem pripojit do diskusie, tak by som sa chcel tiez nieco spytat
> ohladom try ... finally
> Majme nieco taketo:
>
> var
> Obj1: TObj1;
> Obj2: TObj2;
> begin
> Obj1 := TObj1.Create(...);
> try
> try
> ...
> if (NejakaPodmienka) then
> begin
> Obj2 := TObj2.Create(...);
> try
> ...
> finally
> Obj2.Free;
> end;
> end;
> ...
> except
> ShowMessage('Chyba!');
> end;
> finally
> Obj1.Free;
> end;
> end;
>
> No a otazka znie
> Ak sa vyskytne nejaka chyba medzi try ... finally pre Obj2 tak sa odchyti
az
> vtom jedinom except, ale je otazne ci sa predtym este zavola to Obj2.Free
v
> jeho finally, alebo sa rovno skoci do except a Obj2 ostane vysiet v
pamati?
>
> Stevlik Marian
> Software Development Specialist
> MERLIN
> Stefanikova 32
> 150 00 Prague 5
> Czech Republic
> e-mail: marian.stevlik@merlin.cz
> tel: +420 241010111 (181)
> fax: +420 241010165
> ICQ: 38493645
>
>


Odpovedá: Ondrej Kelle

25. 10. 2002 10:39

> var
> Obj1: TObj1;
> Obj2: TObj2;
> begin
> Obj1 := TObj1.Create(...);
> try
> try
> ...
> if (NejakaPodmienka) then
> begin
> Obj2 := TObj2.Create(...);
> try
> ...
> finally
> Obj2.Free;
> end;
> end;
> ...
> except
> ShowMessage('Chyba!');
> end;
> finally
> Obj1.Free;
> end;
> end;
>
> No a otazka znie
> Ak sa vyskytne nejaka chyba medzi try ... finally pre Obj2
> tak sa odchyti az vtom jedinom except, ale je otazne ci
> sa predtym este zavola to Obj2.Free v jeho finally, alebo
> sa rovno skoci do except a Obj2 ostane vysiet v pamati?

Ved si to mozes odkrokovat. Obj2.Free sa zavola este pred tym except blokom.
try..finally prave zaruci, ze finally blok sa vykona bez ohladu na to, ci v
bloku try nastala vynimka.

HTH
TOndrej

Odpovedá: Petr Fejfar

25. 10. 2002 11:45

From: "Ondrej Kelle" <O.Kelle@digitalpublishing.de>

> Skratka, neinicializovany pointer
> ukazuje na blok pameti s nedefinovanym obsahom,

Jen technicka poznamka: Proc s nedefinovanym?

Je-li ten pointer automatickou promennou, tak se alokuje na stacku posunutim
SP a tak
neinicializovany pointer muze stejne dobre
obsahovat napr. odkaz na platnou
(existujici) instanci nektere tridy, ktera se
predavala jako argument popr. self pri nekterem
z predchozich volani podprogramu s vetsi hloubkou vnoreni zasobniku.


Bye, pf


Odpovedá: Ondrej Kelle

25. 10. 2002 12:04

>> Skratka, neinicializovany pointer
>> ukazuje na blok pameti s nedefinovanym obsahom,
>
> Jen technicka poznamka: Proc s nedefinovanym?
>
> Je-li ten pointer automatickou promennou, tak se alokuje na
> stacku posunutim SP a tak neinicializovany pointer muze
> stejne dobre obsahovat napr. odkaz na platnou (existujici)
> instanci nektere tridy, ktera se predavala jako argument popr.
> self pri nekterem z predchozich volani podprogramu s vetsi
> hloubkou vnoreni zasobniku.

Hm, zle som sa vyjadril. Chcel som povedat, ze neinicializovana premenna
typu pointer ukazuje niekam na nahodnu adresu. Moze to byt niekam uplne do
blba, alebo nahodou aj na platnu instanciu, ako hovoris.
Velmi pravdepodobne vsak neukazuje tam, kde to autor ocakaval.
Je to takto spravne alebo som uplne mimo ako ten pointer?  

Dik za opravu.

TOndrej

Odpovedá: Martin Schayna

25. 10. 2002 13:21

----- Original Message -----
From: "Petr Fejfar" <development@callnet.cz>
> Je-li ten pointer automatickou promennou, tak se
> alokuje na stacku posunutim SP a tak neinicializovany
> pointer muze stejne dobre obsahovat napr. odkaz na
> platnou (existujici) instanci nektere tridy, ktera se
> predavala jako argument popr. self pri nekterem
> z predchozich volani podprogramu s vetsi hloubkou
> vnoreni zasobniku.

Nehrajme si se slovicky, proste to znamena ze se
programator nemuze spolehnout co v takovem pointeru
je a rozhodne s tim nemuze pocitat.

Odpovedá: Petr Fejfar

25. 10. 2002 15:29

From: "Martin Schayna" <mschayna@aktis.cz>

> Nehrajme si se slovicky, proste to znamena
> ze se programator nemuze spolehnout co v takovem
> pointeru je a rozhodne s tim nemuze pocitat.

Kdyby tohle bylo kazdemu jasne
(tim nemam na mysli TOndreje), tak se nebudou
v konferenci stale dokola opakovat dotazy
tohoto typu, nehlede na to, ze ve vsech uvadenych
prikladech na neinicializovanou promennou
upozorni prekladac Warningem, tudiz v podstate
neni co resit ani o cem diskutovat.

Bye, pf